//===============================================================================
// Microsoft patterns & practices
// Web Client Software Factory
//-------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//-------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================
using System;
using System.Collections.Generic;
using System.Text;
using WCSFContrib.PageFlow;
using WCSFContrib.PageFlow.Services;
using WCSFContrib.PageFlow.Utils;
using System.Globalization;
using System.Collections.ObjectModel;
using WCSFContrib.PageFlow.Xml.Properties;

namespace WCSFContrib.PageFlow.Xml
{
    public class XmlPageFlow : IPageFlow
    {
        XmlPageFlowInstance _instance;
        INavigationService _navigationService;
        XmlPageFlowDefinition _definition;

        public XmlPageFlow(XmlPageFlowInstance instance, INavigationService navigationService, XmlPageFlowDefinition definition)
        {
            Guard.ArgumentNotNull(instance, "instance");
            _navigationService = navigationService;
            _definition = definition;
            _instance = instance;
        }

        public event EventHandler<PageFlowAbortedEventArgs> Aborted;

        public event EventHandler<PageFlowEventArgs> Started;

        public event EventHandler<PageFlowEventArgs> Completed;

        public event EventHandler<PageFlowEventArgs> Suspended;

        public event EventHandler<PageFlowEventArgs> Resumed;

        public Page CurrentPage
        {
            get
            {
                if (_instance.CurrentView == null)
                    return null;
                return _definition.GetPage(_instance.CurrentView);
            }
        }

        public IPageFlowDefinition Definition
        {
            get { return _definition; }
        }

        public Guid Id
        {
            get { return _instance.InstanceId; }
        }

        public PageFlowStatus Status
        {
            get { return _instance.Status; }
        }

        public System.Collections.ObjectModel.ReadOnlyCollection<string> Transitions
        {
            get { return CurrentPage.Transitions.AsReadOnly(); }
        }

        public PageFlowState UserData
        {
            get { return _instance.UserData; } 
        }

        public XmlPageFlowInstance Instance
        {
            get { return _instance; }
        }

        public void Abort(bool redirectToAbortPage)
        {
            _instance.Abort();

            if (Aborted != null)
                Aborted(this, new PageFlowAbortedEventArgs(Id));

            if (redirectToAbortPage)
            {
                if (_definition.AbortPage.Url != null)
                    _navigationService.RedirectTo(_definition.AbortPage);
            }
        }

        public bool CanRedirectTo(string pageName)
        {
            if (_definition.Constrained)
            {
                if (pageName == CurrentPage.Name)
                {
                    return true;
                }

                return false;
            }
            else
            {
                return true;
            }
        }

        public void Navigate(string transitionName)
        {
            Guard.ArgumentNotNullOrEmptyString(transitionName, "transitionName");

            if (!CurrentPage.Transitions.Contains(transitionName))
            {
                throw new NavigationException(string.Format(CultureInfo.CurrentCulture, "The transition {0} does not exists.", transitionName));
            }

            if (Status == PageFlowStatus.Suspended)
                this.Resume();

            if (Status != PageFlowStatus.Running)
                throw new NavigationException(Resources.CannotNavigateWithoutRunningStatus);

            _instance.CurrentView = _definition.GetPageForTransition(CurrentPage, transitionName, _instance.UserData).Name;

            Persist();

            RedirectToCurrentPage();
        }

        public void RedirectToCurrentPage()
        {
            _navigationService.RedirectTo(CurrentPage);
        }

        public void SetCurrentPage(string pageName)
        {
            if (_definition.Constrained)
            {
                if (pageName != _instance.CurrentView)
                    throw new NavigationException(Resources.CannotSetStateConstrained);
            }
            else
            {
                _instance.CurrentView = pageName;
                Persist();
            }
        }

        public void Start()
        {
            _instance.CurrentView = _definition.StartPage.Name;
            _instance.Start();
            Persist();

            if (Started != null)
                Started(this, new PageFlowEventArgs(this));  
        }

        public void Suspend()
        {
            _instance.Suspend();
            Persist();

            if (Suspended != null)
                Suspended(this, new PageFlowEventArgs(this));
        }

        public void Resume()
        {
            _instance.Resume();

            if (Resumed != null)
                Resumed(this, new PageFlowEventArgs(this));
        }

        public void Complete()
        {
            _instance.Complete();

            if (Completed != null)
                Completed(this, new PageFlowEventArgs(this));
        }

        public void Next()
        {
            Navigate(CurrentPage.DefaultTransition);
        }

        /// <summary>
        /// Determines whether the specified Object is equal to the current XmlPageFlow. 
        /// </summary>
        /// <param name="obj">The object to compare the current instance to.</param>
        /// <returns><see langword="true"/> if the specified Object is equal to the current Object; 
        /// otherwise, <see langword="false"/>.</returns>
        public override bool Equals(object obj)
        {
            XmlPageFlow pf = obj as XmlPageFlow;
            if (pf == null)
            {
                return false;
            }
            else
            {
                return pf.Id.Equals(this.Id);
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        private void Persist()
        {
            _instance.Persist();
        }
    }
}
